import lodash from 'lodash';
import { MessageBox, Message } from 'element-ui';

/**
 * 自定义提示组件
 * @param {String} type 提示类型
 * @param {String} message 提示语句
 */
let messageInstance = null;
export function $showCustomMessage(type, message) {
	const onClose = () => { messageInstance = null };
	!!messageInstance && Message.closeAll();
	messageInstance = Message({ type, message, onClose });
}

/**
 * 生成不重复随机数
 * @param len 随机数长度
 * @returns {string} 生成的随机数
 */
export function $genUUID(len = 32) {
	let id = '';
	let chars = '0123456789abcdef';
	for (let i = 0; i < len; i++) {
		id += chars[Math.floor(Math.random() * chars.length)];
	}
	return id;
}

/**
 * 获取多个数的最小公倍数
 * @param {Array} numbers 需要求公倍数的数组
 * @returns {Number} 最小公倍数
 */
export function $getLCM(numbers) {
	const gcd = (a, b) => {
		if (!b) return a;
		return gcd(b, a % b);
	}
	const lcm = (a, b) => (a * b) / gcd(a, b);
	return numbers.reduce((a, b) => lcm(a, b));
}

/**
 * 对象数组转对象
 * @param {Array} arr 数据数组
 * @param {String} key 转换后对象属性名
 * @param {*} value 转换后对象属性对应数据
 * @returns {Object} 转换后的对象
 */
export function $arrToObject(arr, key = 'code', value = 'value') {
	return lodash.fromPairs(lodash.map(arr, n => [n[key], n[value]]));
}

/**
 * 对象转数组
 * @param {Object} obj 数据对象
 * @param {String} key 转换后数组属性名
 * @param {*} value 转换后数组属性对应数据
 * @returns {Array} 转换后的数组
 */
export function $objToArray(obj, key = 'code', value = 'value') {
	return lodash.map(obj, (n, k) => {
		return {
			[key]: k,
			[value]: n,
		}
	});
}

/**
 * JSON对象转query参数
 * @param {Object} params 传入的JSON参数
 * @returns {String} 转换后的query参数
 */
export function $jsonToQuery(params) {
	let argObject = Object.entries(params || {});
	let validObject = lodash.pickBy(argObject, n => !!n);
	let queryObject = lodash.mapValues(argObject, (value) => `${value.join('=')}`);
	return Object.keys(queryObject).length === 0 ? '' : `?${Object.values(queryObject).join('&')}`;
}

/**
 * query参数转JSON对象
 * @param {String} query 传入的query参数
 * @returns {Object} 转换后的JSON对象
 */
export function $queryToJson(query) {
	const newQuery = query.startsWith('?') ? query.slice(1) : query;
	return lodash.fromPairs(lodash.map(newQuery.split('&'), n => n.split('=')));
}

/**
 * 获取接口返回数据详情
 * @param {Array} data 接口返回数据
 * @returns {Object} 详情数据
 */
export function $detailData(data) {
	return !lodash.isEmpty(data) ? lodash.first(data) : {};
}

/**
 * 文件转BLOB临时路径
 * @param {File} file 文件
 * @returns {Promise} Promise对象
 */
export function $fileToBlobUrl(file) {
	return new Promise((resolve, reject) => {
		let reader = new FileReader();
		reader.onload = function(event) {
			let blob = new Blob([event.target.result], { type: file.type });
			let blobURL = window.URL.createObjectURL(blob);
			resolve(blobURL);
		}
		reader.readAsArrayBuffer(file);
	})
}

/**
 * 返回数组中新增的元素
 * @param {Array} original 原始数组
 * @param {Array} updateArr 新数组
 * @returns {Array} 新增的元素数组
 */
export function $getAddedArr(original, updateArr, tag = 'id') {
	return lodash.differenceWith(updateArr, original, (a, b) => a[tag] === b[tag]);
}

/**
 * 返回数组中删除的元素
 * @param {Array} original 原始数组
 * @param {Array} updateArr 新数组
 * @returns {Array} 删除的元素数组
 */
export function $getDeleteArr(original, updateArr, tag = 'id') {
	return lodash.differenceWith(original, updateArr, (a, b) => a[tag] === b[tag]);
}

/**
 * 获取外部文件后缀
 * @param {String} url 文件在线路径
 * @returns {String} 返回文件后缀
 */
export function $getFileSuffix(url) {
	let reg = /\.([^./?#]+)(?=[?#]|$)/i;
	if (lodash.isEmpty(url)) return null;
	return reg.exec(url)[1];
}

/**
 * 返回数字、英文、中文的顺序
 * aStr,bStr 传入的字符串
 */
export function $sortNumberEnZh(aStr, bStr, flag) {
	const isLetterOrNumberReg = (str) => /^[0-9a-zA-Z]+$/.test(str);
	const isAllChineseStr = (str) => /^[\u4E00-\u9FA5]+$/.test(str);
	const splitStringByNumber = (str, sortByNumericalSize = false) => {
		let strArr = [];
		const REG_STRING_NUMBER_PARTS = /\d+|\D+/g;
		const arr = str?.match(REG_STRING_NUMBER_PARTS) || [];
		for (let i = 0, len = arr.length; i < len; i++) {
			if (isNaN(arr[i])) {
				strArr = strArr.concat(arr[i].split(''));
			} else {
				// Whether to split numbers
				if (!sortByNumericalSize) {
					strArr = strArr.concat(arr[i].split(''));
				} else {
					strArr.push(arr[i]);
				}
			}
		}
		return strArr;
	};
	const compare = (a, b, sortByNumericalSize = true) => {
		let result = 0;
		// 都是数字或字母
		if (isLetterOrNumberReg(a) && isLetterOrNumberReg(b)) {
			return a?.localeCompare(b, 'zh-Hans-CN', { numeric: true });
		}
		// 中文字符串自己比较
		if (isAllChineseStr(a) && isAllChineseStr(b)) {
			return a?.localeCompare(b, 'zh-Hans-CN', { numeric: true });
		}
		const arrA = splitStringByNumber(a, sortByNumericalSize);
		const arrB = splitStringByNumber(b, sortByNumericalSize);
		const length = Math.min(arrA.length, arrB.length);
		for (let i = 0; i < length; i++) {
			const charA = arrA[i];
			const charB = arrB[i];
			// 数字, 字符串排在 中文前面
			if (!isAllChineseStr(charA) && isAllChineseStr(charB)) return -1;
			if (isAllChineseStr(charA) && !isAllChineseStr(charB)) return 1;
			// 中文字符直接比较
			if (isAllChineseStr(charA) && isAllChineseStr(charB)) {
				result = charA?.localeCompare(charB, 'zh-Hans-CN');
			} else {
				// 都不是中文
				result = charA?.localeCompare(charB, 'zh-Hans-CN', { numeric: true });
			}
			if (result !== 0) return result;
		}
		if (arrA.length > arrB.length) return 1;
		if (arrA.length < arrB.length) return -1;
		return 0;
	}
	return compare(aStr, bStr, flag)
}

/**
 * 全屏加载动画
 */
export function $fullLoading() {
	let that = this;
	return {
		loading: null,
		open() {
			this.loading = that.$loading({
				lock: true,
				text: "正在加载...",
				spinner: "el-icon-loading",
				background: "rgba(0, 0, 0, 0.6)",
				customClass: 'custom_full_loading'
			});
			return this;
		},
		close() {
			this.loading.close();
			this.loading = null;
			return this;
		}
	}
}

/**
 * 选择弹出框
 * opt 配置
 */
export function $handleMsgBoxEvent(opt) {
	MessageBox({
		title: opt.title,
		message: opt.message,
		destroyOnClose: true,
		showCancelButton: true,
		cancelButtonText: '取消',
		confirmButtonText: '确定',
		beforeClose: async (action, instance, done) => {
			if (action === 'confirm') {
				instance.confirmButtonLoading = true;
				await opt.confirm();
				instance.confirmButtonLoading = false;
				done();
			} else {
				done();
			}
		}
	}).catch(() => {});
}

/**
 * 判断是否有存在域名
 * path: 文件路径
 */
export function $hasDomainInPath(path) {
	let reg = /^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\n\/?]+)/;
	return reg.test(path);
}